/*
 *  $Id: Scene.cs 574 2009-06-25 10:38:55Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;
using System.IO;

using AgateLib;
using AgateLib.AudioLib;
using AgateLib.DisplayLib;
using AgateLib.InputLib;
using AgateLib.Geometry;

namespace Ragima {
    /// <summary>
    /// Абстрактная сцена (игровой экран)
    /// </summary>
    public abstract class OldScene {
        private List<HotKey> _keys;
        private List<Region> _regions;
        private List<UI.ParticleEmitter> _emitters;
        private Region _curRegion;
        private int _controlCounter;
        private Hint _hint;
        private UI.Cursor _cursor;

        public OldScene() {
            _keys = new List<HotKey>();
            _regions = new List<Region>();
            _emitters = new List<UI.ParticleEmitter>();
            _controlCounter = 0;
            _hint = null;
            _cursor = Data.Cursors.GetCursor("default");
        }

        public bool EnabledControl { get { return _controlCounter <= 0; } }

        public virtual void InitializeScene() {
            ClearHotKeys();
            RegisterHotKey(KeyCode.F5, Application.ToggleFullScreen);
            RegisterHotKey(KeyCode.Escape, Application.ReturnToMenu);

            Mouse.MouseMove += MouseMoveHandler;
            Mouse.MouseDown += MouseDownHandler;
            Mouse.MouseUp += MouseUpHandler;
            Mouse.MouseDoubleClick += MouseDoubleClickHandler;
            Keyboard.KeyDown += KeyDownHandler;
        }

        public virtual void FinalizeScene() {
            Mouse.MouseMove -= MouseMoveHandler;
            Mouse.MouseDown -= MouseDownHandler;
            Mouse.MouseUp -= MouseUpHandler;
            Mouse.MouseDoubleClick -= MouseDoubleClickHandler;
            Keyboard.KeyDown -= KeyDownHandler;
        }

        #region Static methods for play music and sound
        public static void Play(Music music, bool isLooping) {
            if (Application.Config.Sound.DriverEnabled && Application.Config.Sound.MusicEnabled && music != null) {
                music.IsLooping = isLooping;
                music.Volume = CalcVolume(Application.Config.Sound.MusicVolume);
                music.Play();
            }
        }
        public static void Play(SoundBuffer sound) {
            if (Application.Config.Sound.DriverEnabled && Application.Config.Sound.SoundEnabled && sound != null) {
                sound.Volume = CalcVolume(Application.Config.Sound.SoundVolume);
                sound.Play();
            }
        }
        public static void Stop(Music music) {
            if (music != null) {
                music.Stop();
            }
        }
        private static double CalcVolume(int volume) {
            if (volume <= 0) return 0;
            if (volume >= 100) return 1;
            return volume / 100.0;
        }
        #endregion

        public void ClearHotKeys() {
            _keys.Clear();
        }
        public void RegisterHotKey(KeyCode key, SimpleEvent action) {
            _keys.Add(new HotKey(key, action));
        }

        private void MouseMoveHandler(InputEventArgs e) {
            PositionHandler(e.MousePosition);
            HintHandler();
        }
        private void MouseDownHandler(InputEventArgs e) {
            if (_controlCounter > 0) return;
            if (e.MouseButtons == Mouse.MouseButtons.Primary) {
                ClickHandler(_curRegion, true);
            } else if (e.MouseButtons == Mouse.MouseButtons.Secondary) {
                SecondaryClickHandler(_curRegion, true);
            }
        }
        private void MouseUpHandler(InputEventArgs e) {
            if (_controlCounter > 0) return;
            if (e.MouseButtons == Mouse.MouseButtons.Primary) {
                ClickHandler(_curRegion, false);
            } else if (e.MouseButtons == Mouse.MouseButtons.Secondary) {
                SecondaryClickHandler(_curRegion, false);
            }
        }
        private void MouseDoubleClickHandler(InputEventArgs e) {
            if (_controlCounter > 0) return;
            if (e.MouseButtons == Mouse.MouseButtons.Primary && _curRegion != null)
                _curRegion.OnDoubleClick();
        }
        private void KeyDownHandler(InputEventArgs e) {
            if (_controlCounter > 0) return;
            if (e.RepeatCount == 0) {
                foreach (HotKey key in _keys)
                    if (e.KeyCode == key.Key && key.Action != null) {
                        key.Action();
                        return;
                    }
                Region region = FindRegion(e.KeyCode);
                if (region != null) region.OnKeyPress();
            }
        }

        private void PositionHandler(Point point) {
            Region region = FindRegion(point);
            if (region == _curRegion) return;
            if (_curRegion != null) _curRegion.OnMouseLeave();
            _curRegion = region;
            if (_curRegion != null) _curRegion.OnMouseEnter();
        }
        private void HintHandler() {
            _hint = (_curRegion != null) ? _curRegion.GetHint() : null;
        }

        protected virtual void ClickHandler(Region region, bool down) {
            if (region != null) {
                if (down)
                    region.OnClick();
                else
                    region.OnClickUp();
            }
        }
        protected virtual void SecondaryClickHandler(Region region, bool down) {
            if (region != null) {
                if (down)
                    region.OnRightClick();
                else
                    region.OnRightClickUp();
            }
        }

        public void UpdateHint() {
            HintHandler();
        }

        public void EnableControl() {
            _controlCounter--;
        }
        public void DisableControl() {
            _controlCounter++;
        }

        public void NextFrame() {
            Process();
            FrameWait();
            if (Display.RenderTarget != null) {
                Display.BeginFrame();
                try {
                    Draw();
                    _cursor.Draw();
                } finally {
                    Display.EndFrame();
                }
            }
            Core.KeepAlive();
        }

        private DateTime _time = DateTime.Now;
        private void FrameWait() {
            TimeSpan _sleep = Constants.FrameTime - (DateTime.Now - _time);
            if (_sleep > TimeSpan.Zero) System.Threading.Thread.Sleep(_sleep);
            _time = DateTime.Now;
        }

        public virtual void Draw() {
            Display.Clear();
            DrawRegions();
            DrawHint();
        }
        public virtual void Process() {
            ProcessRegions();
            ProcessHint();
        }

        public void DrawHint() {
            if (_hint != null) _hint.Draw();
        }
        public void ProcessHint() {
            if (_hint != null) _hint.Process();
        }

        /// <summary>
        /// Обновление списка регионов
        /// </summary>
        public void UpdateRegions() {
            _regions.Clear();
            UpdateRegions(_regions);
            PositionHandler(Mouse.Position);
        }
        protected virtual void UpdateRegions(List<Region> regions) {}

        public void DrawRegions() {
            for (int i = 0; i < _regions.Count; i++) {
                Region region = _regions[i];
                if (IsTargetRegion(region))
                    region.DrawTarget();
                else
                    region.Draw();
            }
            for (int i = 0; i < _emitters.Count; i++) {
                _emitters[i].Draw();
            }
        }

        protected virtual bool IsTargetRegion(Region region) {
            return false;
        }

        public void ProcessRegions() {
            for (int i = 0; i < _regions.Count; i++) {
                _regions[i].OnProcess();
            }
            for (int i = 0; i < _emitters.Count; i++) {
                _emitters[i].Process();
            }
            _emitters.RemoveAll(delegate(UI.ParticleEmitter emitter) { return emitter.Ended; });
        }

        /// <summary>
        /// Поиск региона по точке
        /// </summary>
        /// <param name="pos">Проверяемая точка</param>
        /// <returns>Найденный регион, либо null, если в этой точке нет региона</returns>
        public Region FindRegion(Point pos) {
            for (int i = _regions.Count-1; i >= 0; i--)
                if (_regions[i].Rect.Contains(pos)) return _regions[i];
            return null;
        }

        /// <summary>
        /// Поиск региона по горячей клавише
        /// </summary>
        /// <param name="key">Проверяемая клавиша</param>
        /// <returns>Найденный регион, либо null, если на эту клавишу нет региона</returns>
        public Region FindRegion(KeyCode key) {
            for (int i = _regions.Count - 1; i >= 0; i--)
                if (_regions[i].HotKey == key)
                    return _regions[i];
            return null;
        }

        /// <summary>
        /// Поиск региона по предикату
        /// </summary>
        public Region FindRegion(Predicate<Region> predicate) {
            for (int i = _regions.Count - 1; i >= 0; i--)
                if (predicate(_regions[i]))
                    return _regions[i];
            return null;
        }

        public void AddEmitter(UI.ParticleEmitter emitter) {
            _emitters.Add(emitter);
        }
    }

    public class HotKey {
        public readonly KeyCode Key;
        public readonly SimpleEvent Action;

        public HotKey(KeyCode key, SimpleEvent action) {
            Key = key;
            Action = action;
        }
    }

}